﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;

namespace StreamBase.SB.Client {
    public static class ToObserverExtensions {

        #region public IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, string sStreamName, ...)
        public static IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, string sStreamName) {
            return Observer.Create<Tuple> (OnEnqueue (streamBaseClient, sStreamName));
        }
        public static IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, string sStreamName, Action onCompleted) {
            if (null == onCompleted)
                throw new ArgumentNullException ("onCompleted");
            return Observer.Create<Tuple> (OnEnqueue (streamBaseClient, sStreamName), onCompleted);
        }
        public static IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, string sStreamName, Action<Exception> onError) {
            if (null == onError)
                throw new ArgumentNullException ("onError");
            return Observer.Create<Tuple> (OnEnqueue (streamBaseClient, sStreamName), onError);
        }
        public static IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, string sStreamName, Action<Exception> onError, Action onCompleted) {
            if (null == onError)
                throw new ArgumentNullException ("onError");
            if (null == onCompleted)
                throw new ArgumentNullException ("onCompleted");
            return Observer.Create<Tuple> (OnEnqueue(streamBaseClient, sStreamName), onError, onCompleted);
        }
        #endregion

        #region public IEnumerable<Tuple> ToObserver<T> (this StreamBaseClient streamBaseClient, string sStreamName, ...)
        public static IObserver<T> ToObserver<T> (this StreamBaseClient streamBaseClient, string sStreamName) where T : IEnumerable<Tuple> {
            return Observer.Create<T> (OnEnqueue<T> (streamBaseClient, sStreamName));
        }
        public static IObserver<T> ToObserver<T> (this StreamBaseClient streamBaseClient, string sStreamName, Action onCompleted) where T : IEnumerable<Tuple> {
            if (null == onCompleted)
                throw new ArgumentNullException ("onCompleted");
            return Observer.Create<T> (OnEnqueue<T> (streamBaseClient, sStreamName), onCompleted);
        }
        public static IObserver<T> ToObserver<T> (this StreamBaseClient streamBaseClient, string sStreamName, Action<Exception> onError) where T : IEnumerable<Tuple> {
            if (null == onError)
                throw new ArgumentNullException ("onError");
            return Observer.Create<T> (OnEnqueue<T> (streamBaseClient, sStreamName), onError);
        }
        public static IObserver<T> ToObserver<T> (this StreamBaseClient streamBaseClient, string sStreamName, Action<Exception> onError, Action onCompleted) where T : IEnumerable<Tuple> {
            if (null == onError)
                throw new ArgumentNullException ("onError");
            if (null == onCompleted)
                throw new ArgumentNullException ("onCompleted");
            return Observer.Create<T> (OnEnqueue<T> (streamBaseClient, sStreamName), onError, onCompleted);
        }
        #endregion

        #region public IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, StreamProperties props, ...)
        public static IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, StreamProperties props) {
            return Observer.Create<Tuple> (OnEnqueue (streamBaseClient, props));
        }
        public static IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, StreamProperties props, Action onCompleted) {
            if (null == onCompleted)
                throw new ArgumentNullException ("onCompleted");
            return Observer.Create<Tuple> (OnEnqueue (streamBaseClient, props), onCompleted);
        }
        public static IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, StreamProperties props, Action<Exception> onError) {
            if (null == onError)
                throw new ArgumentNullException ("onError");
            return Observer.Create<Tuple> (OnEnqueue (streamBaseClient, props), onError);
        }
        public static IObserver<Tuple> ToObserver (this StreamBaseClient streamBaseClient, StreamProperties props, Action<Exception> onError, Action onCompleted) {
            if (null == onError)
                throw new ArgumentNullException ("onError");
            if (null == onCompleted)
                throw new ArgumentNullException ("onCompleted");
            return Observer.Create<Tuple> (OnEnqueue (streamBaseClient, props), onError, onCompleted);
        }
        #endregion

        #region public IEnumerable<Tuple> ToObserver<T> (this StreamBaseClient streamBaseClient, StreamProperties props, ...)
        public static IObserver<T> ToObserver<T> (this StreamBaseClient streamBaseClient, StreamProperties props) where T : IEnumerable<Tuple> {
            return Observer.Create<T> (OnEnqueue<T> (streamBaseClient, props));
        }
        public static IObserver<T> ToObserver<T> (this StreamBaseClient streamBaseClient, StreamProperties props, Action onCompleted) where T : IEnumerable<Tuple> {
            return Observer.Create<T> (OnEnqueue<T> (streamBaseClient, props), onCompleted);
        }
        public static IObserver<T> ToObserver<T> (this StreamBaseClient streamBaseClient, StreamProperties props, Action<Exception> onError) where T : IEnumerable<Tuple> {
            return Observer.Create<T> (OnEnqueue<T> (streamBaseClient, props), onError);
        }
        public static IObserver<T> ToObserver<T> (this StreamBaseClient streamBaseClient, StreamProperties props, Action<Exception> onError, Action onCompleted) where T : IEnumerable<Tuple> {
            return Observer.Create<T> (OnEnqueue<T> (streamBaseClient, props), onError, onCompleted);
        }
        #endregion

        #region static OnEnqueue (..)
        static Action<Tuple> OnEnqueue (StreamBaseClient streamBaseClient, string sStreamName) {
            return OnEnqueue (streamBaseClient, streamBaseClient.GetStreamProperties (sStreamName));
        }
        static Action<Tuple> OnEnqueue (StreamBaseClient streamBaseClient, StreamProperties props) {
            return tuple => streamBaseClient.Enqueue (props, tuple);
        }
        static Action<T> OnEnqueue<T> (StreamBaseClient streamBaseClient, string sStreamName) where T : IEnumerable<Tuple> {
            return OnEnqueue<T> (streamBaseClient, streamBaseClient.GetStreamProperties (sStreamName));
        }
        static Action<T> OnEnqueue<T> (StreamBaseClient streamBaseClient, StreamProperties props) where T : IEnumerable<Tuple> {
            if (typeof (List<Tuple>).IsAssignableFrom (typeof (T)))
                return tuples => streamBaseClient.Enqueue (props, tuples as List<Tuple>);
            else
                return tuples => streamBaseClient.Enqueue (props, tuples.ToList ());
        }
        #endregion
    }
}